#include "stdafx.h"
#include "xml.h"
namespace base
{
	Xml::Xml(void)
	{
	}

	Xml::~Xml(void)
	{
	}
	bool Xml::SetName(LPCWSTR name)
	{
		if(-1!=base::WcsFind(name,L"<")) return 0;
		if(-1!=base::WcsFind(name,L">")) return 0;
		_Name = name;
		return 1;
	}
	bool Xml::SetValue(LPCWSTR value)
	{
		if(-1!=base::WcsFind(value,L"<")) return 0;
		if(-1!=base::WcsFind(value,L">")) return 0;
		_Value = value;
		return 1;
	}
	bool Xml::Set(LPCWSTR name,LPCWSTR value)
	{
		if(-1!=base::WcsFind(name,L"<")) return 0;
		if(-1!=base::WcsFind(name,L">")) return 0;
		if(-1!=base::WcsFind(value,L"<")) return 0;
		if(-1!=base::WcsFind(value,L">")) return 0;
		_Name = name;
		_Value = value;
		return 1;
	}
	Xml* Xml::GetNode(LPCWSTR name,bool always)
	{
		for(int i=0;i<(int)_Nodes.Count();i++)
		{
			if(base::WcsEqual(_Nodes[i].GetName(),name))
				return &_Nodes[i];
		}
		if(always)
			return AddNode(name);
		else
			return 0;
	}
	uint Xml::AddNode(Xml* node,int index)
	{
		return _Nodes.In(node,index);
	}
	Xml* Xml::AddNode(int index)
	{
		return _Nodes.Add(index);
	}
	Xml* Xml::AddNode(LPCWSTR name,int index)
	{
		Xml* node = _Nodes.Add(index);
		node->SetName(name);
		return node;
	}
	Xml* Xml::AddNode(LPCWSTR name,LPCWSTR value,int index)
	{
		Xml* node = _Nodes.Add(index);
		node->SetName(name);
		node->SetValue(value);
		return node;
	}
	bool Xml::DelNode(int index)
	{
		return 1==_Nodes.Delete(index);
	}
	bool Xml::DelNode(LPCWSTR name)
	{
		for(int i=0;i<(int)_Nodes.Count();i++)
		{
			if(base::WcsEqual(_Nodes[i].GetName(),name))
			{
				_Nodes.Delete(i);
				return 1;
			}
		}
		return 0;
	}
	uint Xml::IndexOfNode(Xml* node)
	{
		return _Nodes.IndexOf(node);
	}
	bool Xml::DelNode(Xml* node)
	{
		return _Nodes.Delete(node);
	}
	bool Xml::RemoveNode(uint index)
	{
		return 1==_Nodes.Out(index);
	}
	void Xml::_ToString(base::String& str,int Indent)
	{
		base::String sp;
		for(int i=0;i<Indent;i++)
		{
			sp += L"  ";
		}
		Indent++;
		str = sp;
		str += L"<";
		str += _Name;
		str += L">";
		if(_Value.Length()){
			str += L"\r\n";
			str += sp;
			str += L"  ";
			str += _Value;
		}

		base::String ns;
		for(int i=0;i<(int)_Nodes.Count();i++)
		{
			str += L"\r\n";
			_Nodes[i]._ToString(ns,Indent);
			str += ns;
		}
		str += L"\r\n";
		str += sp;
		str += L"</";
		str += _Name;
		str += L">";
	}
	void Xml::ToString(base::String& ns)
	{
		_ToString(ns,0);
	}
	uint Xml::_FromString(LPCWSTR str,uint len)
	{
		_Nodes.Clear();
		_Name = L"";
		_Value = L"";
		uint left = base::WcsFind(str,L"<");
		if(left>=len) return 0;
		left += 1;
		uint right = base::WcsFind(str+left,L">");
		if(right!=-1) right += left;
		if(right>=(len-left)) return 0;
		_Name.CopyFrom(str+left,right-left);
		base::String back = L"</";
		back += _Name;
		back += L">";
		right++;
		uint bLeft = base::WcsFind(str+right,back);
		if(bLeft!=-1) bLeft += right;
		if(bLeft>=(len-right)) return 0;
		uint vRight = base::WcsFind(str+right,L"<");
		vRight += right;
		_Value.CopyFrom(str+right,vRight-right);
		left = base::WcsFind(str+vRight,L"<");
		if(left!=-1) left += vRight;
		while(left<bLeft){
			Xml* node = _Nodes.Add();
			uint sLen = node->_FromString(str+left,bLeft-left);
			if(sLen==0) break;
			left += sLen;
		}
		return bLeft+_Name.Length()+3;
	}
	bool Xml::Save(LPCWSTR file)
	{
		base::File sf;
		if(!sf.Create(file,CREATE_ALWAYS)) return 0;
		base::String str;
		ToString(str);
		base::Memory<char> buf;
		int len = str.ToMultiByte(&buf);
		return len==sf.Write(buf.Handle(),len);
	}
	bool Xml::FromString(LPCWSTR str)
	{
		base::String ns;
		int len = base::WcsLength(str);
		ns.SetCubage(len);
		int j = 0;
		for(int i=0;i<len;i++)
		{
			if(str[i]=='\r')
				i++;
			if(str[i]=='\n')
			{
				i++;
				while((str[i]=='\t')||(str[i]==' '))
					i++;
			}
			ns[j] = str[i];
			j++;
		}
		ns[j] = 0;
		ns.Realize();
		return 0!=_FromString(ns,ns.Length());
	}
	bool Xml::Load(LPCWSTR file)
	{
		base::File sf;
		if(!sf.Create(file,OPEN_EXISTING)) return 0;
		base::Memory<char> buf;
		int len = sf.Read(&buf);
		base::String str;
		str.FromMultiByte(buf,len);
		FromString(str);
		return 1;
	}
	void Xml::SetIntValue(int v)
	{
		_Value.Format(L"%u",v);
	}
	int Xml::GetIntValue()
	{
		return _Value.ToInt32(10,0);
	}
	void Xml::SetDoubleValue(double v)
	{
		_Value.Format(L"%f",v);
	}
	double Xml::GetDoubleValue()
	{
		return _Value.ToFloat();
	}
	void Xml::SetBinValue(const void* data,int len)
	{
		_Value.HexBinary(data,len);
	}
	int Xml::GetBinValue(void* data)
	{
		return _Value.ToBinary(data);
	}
	void Xml::SetNodeInt(LPCWSTR name,int v)
	{
		Xml* node = GetNode(name);
		if(!node) 
			node = AddNode(name);
		node->SetIntValue(v);
	}
	bool Xml::GetNodeInt(LPCWSTR name,int* v)
	{
		Xml* node = GetNode(name);
		if(!node) return 0;
		*v = node->GetIntValue();
		return 1;
	}
	void Xml::SetNodeDouble(LPCWSTR name,double v)
	{
		Xml* node = GetNode(name);
		if(!node) 
			node = AddNode(name);
		node->SetDoubleValue(v);
	}
	bool Xml::GetNodeDouble(LPCWSTR name,double* v)
	{
		Xml* node = GetNode(name);
		if(!node) return 0;
		*v = node->GetDoubleValue();
		return 1;
	}
	void Xml::SetNodeBin(LPCWSTR name,const void* data,int len)
	{
		Xml* node = GetNode(name);
		if(!node) 
			node = AddNode(name);
		node->SetBinValue(data,len);
	}
	int Xml::GetNodeBin(LPCWSTR name,void* data)
	{
		Xml* node = GetNode(name);
		if(!node) return 0;
		return node->GetBinValue(data);
	}
	bool Xml::SetNodeValue(LPCWSTR name,LPCWSTR v)
	{
		Xml* node = GetNode(name);
		if(!node) 
			node = AddNode(name);
		return node->SetValue(v);
	}
	LPCWSTR Xml::GetNodeValue(LPCWSTR name)
	{
		Xml* node = GetNode(name);
		if(!node) return 0;
		return node->GetValue();
	}
}
